package schuchert.agent;

import java.io.PrintStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;

public class ConfigurableClassFileTransformerRedirector {

    public static final String DEST_CLASS_PROPERTY_NAME = "schuchert.ClassFileTransformer";

    static final String INSTANTIATION_ERROR = "Unable to instantiate: %s\n";
    static final String MISSING_SYSTEM_PROPERTY = "Please check setting for system property: %s\n";
    static final String EXAMPLE_MESSAGE = "e.g. -D%s=%s\n";
    
    static PrintStream ERROR_OUT = System.err;
    static String[] MISSING_PROPERTY_CLASS_NAME_ARRAY = { NullClassFileTransformer.class.getName() };

    public static void premain(String agentArguments, Instrumentation instrumentation) {
        for (String className : getClassNames()) {
            addOneClassFileTransformer(instrumentation, className);
        }
    }

    private static void addOneClassFileTransformer(Instrumentation instrumentation, String className) {
        ClassFileTransformer classFileTransformer = createTargetTransformer(className);
        instrumentation.addTransformer(classFileTransformer);
    }

    private static ClassFileTransformer createTargetTransformer(String className) {
        ClassFileTransformer targetTransformer = null;

        if (className != null) {
            try {
                Class<?> targetTransformerClass = Class.forName(className);
                targetTransformer = (ClassFileTransformer) targetTransformerClass.newInstance();
            } catch (Exception e) {
                reportException(e, className);
            }
        }

        if (targetTransformer == null) {
            targetTransformer = new NullClassFileTransformer();
        }

        return targetTransformer;

    }

    private static String[] getClassNames() {
        String classNameList = System.getProperty(DEST_CLASS_PROPERTY_NAME);

        if (classNameListMissingOrEmpty(classNameList)) {
            reportUsage();
            return MISSING_PROPERTY_CLASS_NAME_ARRAY;
        }

        String[] classNames = classNameList.split(":");
        for (int i = 0; i < classNames.length; ++i) {
            classNames[i] = classNames[i].trim();
        }
        return classNames;
    }

    private static boolean classNameListMissingOrEmpty(String classNameList) {
        return classNameList == null || classNameList.trim().length() == 0;
    }

    private static void reportException(Exception e, String className) {
        e.printStackTrace(ERROR_OUT);
        ERROR_OUT.printf(INSTANTIATION_ERROR, className);
        reportUsage();
    }

    private static void reportUsage() {
        ERROR_OUT.printf(MISSING_SYSTEM_PROPERTY, DEST_CLASS_PROPERTY_NAME);
        ERROR_OUT.printf(EXAMPLE_MESSAGE, DEST_CLASS_PROPERTY_NAME, NullClassFileTransformer.class.getName());
    }
}
